using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 添加或移除buff
    /// 参数组1:1：buff目标：（1.玩家，2.所有队员，3.队长，4：实体）2：操作类型（1.添加，2.移除）3：实体tag(仅参数1为4时有效)
    /// 参数组2：buff cid列表
    /// </summary>
    public class ExecAddOrRemoveBuff : BaseServiceExecution
    {
        public override void Execute(LevelRegion region, LevelPlayer player)
        {
            var config = _config as ExecParamAddOrRemoveBuff;
            if (config.buffs == null || config.buffs.Count == 0)
            {
                LogicLog.LogError("添加或移除buff失败，buff列表不能为空。");
                return;
            }
            LevelBuffHostType hostType = (LevelBuffHostType)config.hostType;
            LevelBuffOperationType opType = (LevelBuffOperationType)config.opType;
            int tagOrMcid = 0;
            if (hostType == LevelBuffHostType.Entity)
            {
                if (!config.tagOrMcid.TryGetValue(triggerEntity, out tagOrMcid))
                {
                    LogicLog.LogError("添加或删除buff出错，参数1为实体，但无法获取到tagOrMcid.");
                    return;
                }
                if (tagOrMcid == 0 && triggerEntity == null)
                {
                    LogicLog.LogError($"添加或删除buff出错，仅由实体触发的服务可支持tag==0。");
                    return;
                }
                if (opType != LevelBuffOperationType.Remove && tagOrMcid == -1)
                {
                    LogicLog.LogError($"添加或删除buff出错，仅为实体移除buff时支持tag == -1。");
                    return;
                }
            }
            if ((hostType == LevelBuffHostType.Player || hostType == LevelBuffHostType.AllHeroes || hostType == LevelBuffHostType.SingleHero) && player == null)
            {
                LogicLog.LogError("添加或删除buff出错，player == null。buff目标为玩家，队伍，英雄时，必须由玩家主动触发服务。");
                return;
            }
            if (opType != LevelBuffOperationType.Add && opType != LevelBuffOperationType.Remove)
            {
                LogicLog.LogError($"添加或删除buff出错，opType非法：{opType}");
                return;
            }
            List<BaseLevelFunctionHost> hosts = ListPool<BaseLevelFunctionHost>.Get();
            {
                List<LevelBuffChangeParam> changes = ListPool<LevelBuffChangeParam>.Get();
                {
                    region.GetBuffHost(hostType, player, tagOrMcid, triggerEntity, hosts);
                    //AllHeroes是为了方便策划配置，实际的操作是遍历英雄，而同步时的类型是单个英雄（多次）。
                    //其实原则上同步的HostType和添加操作的HostType应该是两个枚举，但这里相当于省事了，不然两个枚举大部分值是相同的含义也容易让人困惑
                    if (hostType == LevelBuffHostType.AllHeroes)
                        hostType = LevelBuffHostType.SingleHero;
                    for (int i = 0; i < hosts.Count; i++)
                    {
                        BaseLevelFunctionHost host = hosts[i];
                        for (int j = 0; j < config.buffs.Count; j++)
                        {
                            int buffCid = config.buffs[j];
                            if (opType == LevelBuffOperationType.Add)
                            {
                                bool isAdd = hosts[i].AddBuff(buffCid,
                                    out var changedBuff, out var removeBuffCid);

                                //如果isAdd == true说明是真正意义上的添加（buff count + 1），否则添加失败，此时要看out参数，如果changeBuff有值，说明是增加了堆叠层数，否则添加完全失败。
                                //removeBuffCid代表添加过程中因为覆盖移除了buff，仅在添加成功时发生。
                                LevelBuffOperationType realOpType = isAdd ?
                                    LevelBuffOperationType.Add :
                                    (changedBuff != null ? LevelBuffOperationType.AddStack : LevelBuffOperationType.None);

                                if (realOpType != LevelBuffOperationType.None)
                                {
                                    LevelBuffChangeParam param = new LevelBuffChangeParam(hostType, host,
                                        realOpType, changedBuff, removeBuffCid);
                                    changes.Add(param);
                                }
                            }
                            else
                            {
                                if (hosts[i].RemoveBuff(buffCid))
                                {
                                    LevelBuffChangeParam param = new LevelBuffChangeParam(hostType, host,
                                        LevelBuffOperationType.Remove,
                                        null, buffCid);
                                    changes.Add(param);
                                }
                            }
                        }
                    }
                    if (changes.Count > 0)
                    {
                        region.NotifyBuffChange(changes);
                    }
                    ListPool<LevelBuffChangeParam>.Put(changes);
                }
                ListPool<BaseLevelFunctionHost>.Put(hosts);
            }
        }
    }
}
